﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Media;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using HandyControl.Controls;
using HandyControl.Data;
using HandyControl.Tools;
using OpenAiClient.Events;
using OpenAiClient.Models;
using OpenAiClient.Repositories;
using OpenAiClient.Services;
using OpenAiClient.Tools;
using OpenAiClient.Util.Json;
using OpenAiClient.Util.Security;
using Prism.Commands;
using Prism.Events;
using Prism.Mvvm;

namespace OpenAiClient.ViewModels
{
    internal class SearchViewModel : BindableBase
    {
        public event Action<FrameworkElement> MessageSelected = (_) => { };

        public DelegateCommand QueryCmd { get; }
        public DelegateCommand CopyMessageCommand { get; }
        public DelegateCommand<KeyEventArgs> SendStringCmd { get; }
        public DelegateCommand<RoutedEventArgs> ReadMessageCmd { get; }
        public DelegateCommand<RoutedEventArgs> SelectMessageCmd { get; }

        public ObservableCollection<ChatInfoModel> ChatInfos { get; }

        public string? ChatString
        {
            get => _chatString;
            set => SetProperty(ref _chatString, value);
        }

        public string? RequestTip
        {
            get => _requestTip;
            set => SetProperty(ref _requestTip, value);
        }

        public Visibility RequestVisibility
        {
            get => _requestVisibility;
            set => SetProperty(ref _requestVisibility, value);
        }

        public Visibility RegisterVisibility
        {
            get => _registerVisibility;
            set => SetProperty(ref _registerVisibility, value);
        }

        private string? _chatString;
        private string? _requestTip;
        private Visibility _requestVisibility = Visibility.Collapsed;
        private Visibility _registerVisibility = Visibility.Visible;
        private int _requestCount; //请求个数

        private ChatInfoModel? _currentChatInfoModel;

        private readonly string _id = Guid.NewGuid().ToString();

        private readonly IConfigService _configService;
        private readonly IHttpService _httpService;
        private readonly IRepository<HistoryModel> _historyRepository;
        private readonly IEventAggregator _eventAggregator;

        public SearchViewModel(
            IConfigService configService,
            IHttpService httpService,
            IStatisticsService statisticsService,
            IRepository<HistoryModel> historyRepository,
            IEventAggregator eventAggregator
        )
        {
            _configService = configService;
            _httpService = httpService;
            _historyRepository = historyRepository;
            _eventAggregator = eventAggregator;

            statisticsService.RegisterSuccess += () => { RegisterVisibility = Visibility.Collapsed; };

            QueryCmd = new DelegateCommand(OnQueryAsync);
            CopyMessageCommand = new DelegateCommand(OnCopyMessage);
            SendStringCmd = new DelegateCommand<KeyEventArgs>(OnSendStringAsync); //发送消息
            ReadMessageCmd = new DelegateCommand<RoutedEventArgs>(OnReadMessage); //读取消息(点击)
            SelectMessageCmd = new DelegateCommand<RoutedEventArgs>(OnSelectMessage); //右键选取
            ChatInfos = new ObservableCollection<ChatInfoModel>();
        }

        private async void OnSendStringAsync(KeyEventArgs e)
        {
            if (e.Key == Key.Enter)
            {
                await DoQueryAsync();
            }
        }

        private void OnReadMessage(RoutedEventArgs e)
        {
            if (e.OriginalSource is FrameworkElement { Tag: ChatInfoModel info })
            {
                if (info.Type == ChatMessageType.Image)
                {
                    new ImageBrowser(new Uri(info.Enclosure?.ToString() ?? string.Empty))
                    {
                        Owner = WindowHelper.GetActiveWindow()
                    }.Show();
                }
                else if (info.Type == ChatMessageType.Audio)
                {
                    var player = new SoundPlayer(info.Enclosure?.ToString() ?? string.Empty);
                    player.PlaySync();
                }
            }
        }

        private void OnSelectMessage(RoutedEventArgs e)
        {
            if (e.OriginalSource is not FrameworkElement control)
            {
                return;
            }

            _currentChatInfoModel = control.DataContext as ChatInfoModel;
            if (_currentChatInfoModel != null)
            {
                MessageSelected.Invoke(control);
            }
        }

        private void OnCopyMessage()
        {
            if (_currentChatInfoModel is { Message: { } })
            {
                Clipboard.SetDataObject(_currentChatInfoModel.Message, true);
                _eventAggregator.GetEvent<ShowGrowlSuccessEvent>().Publish("消息已拷贝到剪切板");
            }
        }

        private async void OnQueryAsync()
        {
            await DoQueryAsync();
        }

        private async Task DoQueryAsync()
        {
            if (string.IsNullOrWhiteSpace(_configService.AccountId))
            {
                var text = $@"请求服务器失败(Error code = {Constants.ErrorNotRegister})";
                _eventAggregator.GetEvent<ShowGrowlWarningEvent>().Publish(text);
                return;
            }

            if (string.IsNullOrEmpty(ChatString))
            {
                return;
            }

            var chatString = ChatString;
            ChatString = string.Empty;

            var info = new ChatInfoModel
            {
                Message = chatString,
                SenderId = _id,
                Type = ChatMessageType.String,
                Role = ChatRoleType.Sender
            };
            ChatInfos.Add(info);

            var aesKey = _configService.AesKey;
            var question = SafeDataHelper.Encrypt(chatString, aesKey);
            var apiUrl = SafeDataHelper.Encrypt(_configService.ApiUrl, aesKey);
            var apiKey = SafeDataHelper.Encrypt(_configService.ApiKey, aesKey);
            AddRequest();

            var queryParamDictionary = new Dictionary<string, object>
            {
                { "Question", question },
                { "Model", _configService.ChatModel }
            };
            if (!string.IsNullOrWhiteSpace(apiUrl))
            {
                queryParamDictionary.Add("ApiUrl", apiUrl);
            }

            if (!string.IsNullOrWhiteSpace(apiKey))
            {
                queryParamDictionary.Add("ApiKey", apiKey);
            }

            var tokenSource = new CancellationTokenSource();
            if (_configService.RequestTimeout > 0)
            {
                tokenSource.CancelAfter(_configService.RequestTimeout * 1000);
            }

            try
            {
                var url = $@"{_configService.WebApiUrl}/api/proxy/chat/{_configService.AccountId}";
                var ret = await _httpService.GetAsync(url, queryParamDictionary, tokenSource.Token);
                if (tokenSource.IsCancellationRequested)
                {
                    info = new ChatInfoModel
                    {
                        Message = "Http请求超时",
                        SenderId = _id,
                        Type = ChatMessageType.String,
                        Role = ChatRoleType.Receiver
                    };
                    ChatInfos.Add(info);
                    return;
                }

                string correctRet;
                if (ret.Item1)
                {
                    correctRet = SafeDataHelper.Decrypt(ret.Item2, aesKey);
                }
                else
                {
                    var response = JsonHelper.DeserializeObject<ProblemResponse>(ret.Item2);
                    var detail = response.Detail ?? string.Empty;
                    correctRet = SafeDataHelper.Decrypt(detail, aesKey);
                }

                //添加结果
                var message = ret.Item1
                    ? correctRet.TrimStart('\n').TrimStart('\n')
                    : $"获取结果失败：{correctRet}";
                info = new ChatInfoModel
                {
                    Message = message,
                    SenderId = _id,
                    Type = ChatMessageType.String,
                    Role = ChatRoleType.Receiver
                };
                ChatInfos.Add(info);

                //添加搜索结果到数据库
                var answer = ret.Item1
                    ? correctRet.TrimStart('\n').TrimStart('\n')
                    : string.Empty;
                var errorMessage = ret.Item1
                    ? string.Empty
                    : correctRet;
                await AddResult2Db(chatString, answer, errorMessage, ret.Item1);
            }
            catch (Exception e)
            {
                var text = $@"请求服务器异常：{e.Message})";
                _eventAggregator.GetEvent<ShowGrowlWarningEvent>().Publish(text);
            }
            finally
            {
                tokenSource.Dispose();
                RemoveRequest();
            }
        }

        private void AddRequest()
        {
            _requestCount++;
            RequestTip = $@"正在请求服务器({_requestCount})...";
            RequestVisibility = Visibility.Visible;
        }

        private void RemoveRequest()
        {
            _requestCount--;
            RequestTip = $@"正在请求服务器({_requestCount})...";
            RequestVisibility = _requestCount > 0 ? Visibility.Visible : Visibility.Collapsed;
        }

        private async Task AddResult2Db(string question, string answer, string errorMessage, bool success)
        {
            var model = new HistoryModel()
            {
                Id = $"{Guid.NewGuid()}".Replace("-", ""),
                Question = question,
                Answer = answer,
                ErrorMessage = errorMessage,
                IsSuccess = success ? (byte)1 : (byte)0,
                CreateTime = DateTime.Now
            };
            _historyRepository.Add(model);
            await _historyRepository.SaveAsync();
        }
    }
}
